package Data;

import java.io.*;
import java.util.*;

/**
 * @Auther: MFM
 * @Date: 2021/8/7 - 08 - 07 - 14:41
 * @version: 1.0
 */

public class DataManage {
    /*
        1.建表
        2.往表中插入数据，对数据进行修改、删除、添加等操作
        应用操作逻辑：进入系统1.建表 2.查看表 2.1 选择表进入，进入一张表后，就可以对该表进行数据的维护（增删改查）
        3.退出系统
     */
    public static void main(String[] args) throws Exception {
        new DataManage().start();

    }

    //首先创建一个键盘输入类
    private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    //创建一个List集合，用于存储当前系统中已有哪些表
    private List<String> tableList = new ArrayList<>();
    //创建一个关于表与表结构之间的映射集合
    private Map<String, List<Column>> map = new HashMap<>();


    private void init() throws Exception {
        File file = new File("./file/data/tables.txt");
        if (!file.exists()) {
            file.createNewFile();
        }
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line = null;
        while ((line = reader.readLine()) != null) {
            this.tableList.add(line);
        }
        reader.close();
    }

    public void start() throws Exception {
        init();
        boolean flag = true;
        String operate = "";
        while (flag) {
            System.out.println("欢迎使用数据库1.0");
            System.out.println("1、新建表 2、表操作 3、退出系统");
            operate = reader.readLine();
            switch (operate) {
                case "1":
                    this.createTable();
                    break;
                case "2":
                    this.operateTable();
                    break;
                case "3":
                    flag = false;
                    break;
            }


        }
        System.out.println("谢谢使用欢迎下次再来");
    }

    private void operateTable() throws Exception {
        /*
            列出当前数据库中已经存在的表
            让用户选择一张表进行操作
            1.查看表中所有的数据 2.删除指定的行 3.修改指定的行 4.增加新的一行
            再返回到操作表的选项上
         */
        boolean flag = true;
        while (flag) {
            System.out.println("表操作：1、查询所有表 2、表数据操作 3、退出表操作");
            String operate = this.reader.readLine();
            switch (operate) {
                case "1":
                    this.queryTables();
                    break;
                case "2":
                    this.queryTables();
                    this.operateTableData();
                    break;
                case "3":
                    flag = false;
                    break;
            }
        }
    }

    private void operateTableData() throws Exception {
        System.out.println("请选择表进行操作,输入表对应的序号");
        int index = Integer.parseInt(this.reader.readLine());
        String tableName = null;
        try {
            tableName = this.tableList.get(index - 1);
        } catch (Exception ex) {
            System.out.println("要操作的表不存在！");
            return;
        }
        System.out.println("请选择对" + tableName + "的操作:1、查询表中所有数据 2、删除指定数据 3、修改指定数据 4、添加新的数据");
        String operate = this.reader.readLine();
        switch (operate) {
            case "1":
                queryTableRow(tableName);
                break;
            case "2":
                deleteData(tableName);
                break;
            case "3":
                updateData(tableName);
                break;
            case "4":
                List<Integer> list = this.queryTableRow(tableName);
                this.addData(tableName);
                break;
        }
    }

    private void updateData(String tableName) throws Exception{
        List<Integer> list = queryTableRow(tableName);
        int max = 0;
        int size = list.size()-1;
        while (max == 0){
            max = list.get(size);
            size--;
        }
        System.out.println("请输入要修改的数据的序号");
        int num = Integer.parseInt(this.reader.readLine());
        if (num < 1 || num > max) {
            System.out.println("要修改的数据记录不存在！");
        }else {
            int rowLength = rowLength(tableName);
            RandomAccessFile raf = new RandomAccessFile(new File("./file/data/" + tableName + "_data.txt"), "rw");
            int index = 0;
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i) == num) {
                    index = i;
                    break;
                }
            }
            long position = rowLength * index;
            raf.seek(position);
            //修改行的数据，就需要用到表结构
            List<Column> cols = queryTableStruct(tableName);
            StringBuilder builder = new StringBuilder();
            for (Column col : cols) {
                byte[] bts =new byte[col.getLength()];
                raf.read(bts);
                String value = new String(bts);
                col.setValue(value);
                //读取的同时，直接询问该列是否要进行修改
                System.out.println("当前列:"+col.getColumnName()+",值为:"+col.getValue()+",是否修改？Y/N");
                String operate = this.reader.readLine();
                if("Y".equalsIgnoreCase(operate)){
                    System.out.println("请输入新的"+col.getColumnName()+"的值:");
                    value = this.reader.readLine();
                    value = this.dealString(value,col.getLength());
                    col.setValue(value);
                }
                builder.append(col.getValue());
            }
            //改行数据读取完毕
            raf.seek(position);
            raf.write(builder.toString().getBytes());
            raf.close();
            System.out.println("数据修改成功");
        }
    }

    private void deleteData(String tableName) throws Exception {
        List<Integer> list = queryTableRow(tableName);
        int max = 0;
        int size = list.size()-1;
        while (max == 0){
            max = list.get(size);
            size--;
        }
        //提示用户输入要删除的记录，输入序号
        System.out.println("请输入要删除的数据的序号");
        int num = Integer.parseInt(this.reader.readLine());
        if (num < 1 || num > max) {
            System.out.println("要删除的数据记录不存在！");
        } else {
            /*
                删除整行的逻辑，使用一个空的字符串，来代替原有的有数据的
                字符串，代替的时候，需要计算要略过的记录指针位置
             */
            int rowLength = rowLength(tableName);
            //修改，使用空的字符串，来代替这个有数据的字符串
            RandomAccessFile raf = new RandomAccessFile(new File("./file/data/" + tableName + "_data.txt"), "rw");
            int index = 0;
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i) == num) {
                    index = i;
                    break;
                }
            }
            long position = rowLength * index;
            raf.seek(position);
            StringBuilder builder = new StringBuilder("");
            for (int i = 0; i <rowLength-1 ; i++) {
                builder.append(" ");
            }
            raf.write(builder.toString().getBytes());
            raf.close();
            System.out.println("数据删除成功！");
        }
    }

    private int rowLength(String tableName) throws Exception {
        int rowLength = 0;
        List<Column> columns = queryTableStruct(tableName);
        //来计算一个行的总长度
        for (Column column : columns) {
            rowLength += column.getLength();
        }
        rowLength++;
        return rowLength;
    }

    private void addData(String tableName) throws Exception {
        List<Column> columns = queryTableStruct(tableName);
        StringBuilder builder = new StringBuilder("");
        for (Column column : columns) {
            System.out.println("请输入" + column.getColumnName() + "的值，该值的长度为：" + column.getLength());
            String value = this.reader.readLine();
            value = this.dealString(value, column.getLength());
            builder.append(value);
        }
        builder.append("\n");
        File dataFile = new File("./file/data/" + tableName + "_data.txt");
        PrintWriter writer = new PrintWriter(new FileWriter(dataFile, true));
        writer.print(builder.toString());
        writer.close();
    }

    private String dealString(String value, int byteLength) throws Exception {
        int size = value.getBytes().length;
        if (size > byteLength) {
            throw new Exception("数据存储失败，超过长度");
        }
        if (size == byteLength) {
            return value;
        }

        StringBuilder builder = new StringBuilder(value);
        for (int i = 0; i < byteLength - size; i++) {
            builder.append(" ");
        }
        return builder.toString();
    }

    private List<Column> queryTableStruct(String tableName) throws Exception {
        List<Column> columns = map.get(tableName);
        if (columns == null) {
            //表示当前系统中尚未存储该表的结构信息，需要读取表结构信息，并存储在系统中
            File structFile = new File("./file/data/" + tableName + ".txt");
            BufferedReader reader = new BufferedReader(new FileReader(structFile));
            List<Column> list = new ArrayList<>();
            String column = null;
            while ((column = reader.readLine()) != null) {
                String[] strs = column.split("-");
                Column col = new Column(strs[0], Integer.parseInt(strs[1]));
                list.add(col);
            }
            reader.close();
            this.map.put(tableName, list);
            columns = list;
        }
        return columns;
    }


    private List<Integer> queryTableRow(String tableName) throws Exception {
        //打印表中所有的数据，把表的头，把列名打印出来
        List<Column> columns = queryTableStruct(tableName);
        //打印表头
        for (Column col : columns) {
            System.out.print(col.getColumnName() + "\t");
        }
        System.out.println();
        List<Integer> rowList = new ArrayList<>();
        //打印表数据
        File dataFile = new File("./file/data/" + tableName + "_data.txt");
        BufferedReader reader = new BufferedReader(new FileReader(dataFile));
        String row = null;
        int index = 1;
        while ((row = reader.readLine()) != null) {
            if (row.matches("^\\s+$")) {
                rowList.add(0);
            } else {
                rowList.add(index);
                System.out.println("序号" + index + "\t" + row);
                index++;
            }
        }
        reader.close();
        return rowList;
    }

    private void queryTables() throws Exception {
        System.out.println("当前数据库已存在表为:");
        int index = 1;
        for (String tableName : tableList) {
            System.out.println("序号:" + index + "\t表名:" + tableName);
            index++;
        }
    }

    private void createTable() throws Exception {
        /*
            新建表操作的逻辑:首先输入一个表名，查看当前该表是否存在，如果存在提示，表名已经存在
            否则，提示新建的表的结构是怎么样，输入字段，输入字段的时候，字段名不能重复，每个字段长度多少

            首先要有一个表来记录数据库中，都有哪些表，使用一个tables文件来记录数据库中已经存在的表
         */
        System.out.println("请输入要新建立的表名");
        String tableName = this.reader.readLine();
        if (tableList.contains(tableName)) {
            System.out.println("要创建的表已存在");
        } else {
            //创建新表的结构文件，创建新表的数据文件，如果是结构文件，就直接使用表名作为文件名，如果是数据文件，表名_.txt作为数据表名
            File structFile = new File("./file/data/" + tableName + ".txt");
            structFile.createNewFile();
            //创建数据文件
            File dataFile = new File("./file/data/" + tableName + "_data.txt");
            dataFile.createNewFile();
            this.tableList.add(tableName);
            //在数据库的tables文件中，加入该表
            PrintWriter writer = new PrintWriter("./file/data/tables.txt");
            writer.println(tableName);
            writer.close();
            //为创建的表，定义表的结构信息，表结构的信息在文件中要存储，在系统中也要存储
            String operate = "Y";
            List<Column> list = new ArrayList<>();
            while ("Y".equalsIgnoreCase(operate)) {
                System.out.println("请输入列名");
                String columnName = this.reader.readLine();
                System.out.println("请输入" + columnName + "的长度(字节长度):");
                int length = Integer.parseInt(this.reader.readLine());
                Column column = new Column(columnName, length);
                list.add(column);
                System.out.println("是否继续添加列名？Y/N");
                operate = this.reader.readLine();
            }
            map.put(tableName, list);
            PrintWriter printWriter = new PrintWriter(structFile);
            for (Column column : list) {
                printWriter.println(column);
            }
            printWriter.close();
        }
    }
}
